package server

import (
	"fmt"
	"sync"
)

const (
	AccessTokenPrefix = "ACCESSTOKEN_"
	PlayerStatNomal   = PlayerStat(0)
	PlayerLost        = PlayerStat(1)
	PlayerQuit        = PlayerStat(2)
)

type PlayerStat int

type GameFactory interface {
	NewGame(player *Player, args Args) (Game, Exception)
	Free(game Game)
}

type Args map[string][]int

func (args Args) Exist(s string) bool {
	_, exist := args[s]
	return exist
}

func (args Args) Store(s string, v []int) {
	args[s] = v
}

func (args Args) Load(s string) []int {
	return args[s]
}

func (args Args) Delete(s string) {
	delete(args, s)
}

type Game interface {
	Id() string
	Name() string
	JoinGame(player *Player) Exception
	ResumeGame(player *Player) Exception
	Play(player *Player, msg *Message) error
	Broadcast(skip *Player, mt uint16, data interface{}) error
	Players() []*Player
	LivePlayersN() int
	GameOver() bool
	GetOwner() *Player
}

type Player struct {
	Id           string
	NickName     string
	No           string
	Session      *Session
	UserInfo     *User
	CurrentClub  *CurrentClub
	Mutex        sync.Mutex
	CurrentScore int
	RoundOfScore int
	Wins         int
	Stat         PlayerStat
}

func NewPlayer(session *Session, token string) (*Player, Exception) {
	ls, err := UserLoginStatus(token)
	if err != nil {
		return nil, err
	}
	u, err := UserInfoByUid(ls.Uid)
	if err != nil {
		return nil, err
	}
	if u.CurrentClubId == "" {
		return nil, InvalidOptException
	}
	club, err := CurrentClubInfo(u.Id, u.CurrentClubId)
	if err != nil {
		return nil, err
	}
	player := &Player{
		Id:          u.Id,
		No:          u.No,
		NickName:    u.NickName,
		Session:     session,
		UserInfo:    u,
		CurrentClub: club,
		Stat:        PlayerStatNomal,
	}
	return player, nil
}

func (player *Player) Unicast(a interface{}, mt uint16) error {
	defer player.Session.Flush()
	return SendOK(player.Session, a, mt)
}

func (player *Player) SendException(ex Exception, mt uint16) error {
	defer player.Session.Flush()
	return SendException(player.Session, ex, mt)
}

func (player *Player) Eq(a *Player) bool {
	if a == nil {
		return false
	}
	return player.Id == a.Id
}

func (player *Player) Destroy() {
	player.Stat = PlayerQuit
	player.Session.Close()
}

func (player *Player) Win() {
	player.Wins++
}

func (player *Player) AddScore(n int) {
	player.RoundOfScore += n
	player.CurrentScore += n
}

func (player *Player) NextRound() {
	player.CurrentScore = 0
	//	player.Wins = 0
}

func (player *Player) UpdateUserInfo() error {
	var u User
	exist, err := DBEngine.ID(player.Id).Get(&u)
	if err != nil {
		return err
	}
	if !exist {
		return fmt.Errorf("用户id(%s)不存在", player.Id)
	}
	player.UserInfo = &u
	return nil
}
